# minesweeper.py
import random
import pygame
import sys


class Minesweeper:
    def __init__(self, width=10, height=10, mines=10):
        """
        初始化扫雷游戏

        Args:
            width: 游戏区域宽度（格子数）
            height: 游戏区域高度（格子数）
            mines: 地雷数量
        """
        self.width = width
        self.height = height
        self.mines = mines
        self.board = [[0 for _ in range(width)] for _ in range(height)]
        self.revealed = [[False for _ in range(width)] for _ in range(height)]
        self.flagged = [[False for _ in range(width)] for _ in range(height)]
        self.game_over = False
        self.win = False
        self.first_click = True

        # 初始化pygame
        pygame.init()
        self.cell_size = 30
        self.window_width = self.width * self.cell_size
        self.window_height = self.height * self.cell_size + 50  # 额外空间显示信息
        self.screen = pygame.display.set_mode((self.window_width, self.window_height))
        pygame.display.set_caption("扫雷游戏")

        # 字体设置
        self.font = pygame.font.SysFont('Arial', 20)
        self.big_font = pygame.font.SysFont('Arial', 30)

        # 颜色定义
        self.colors = {
            'background': (200, 200, 200),
            'grid': (150, 150, 150),
            'revealed': (220, 220, 220),
            'mine': (255, 0, 0),
            'flag': (0, 0, 255),
            'text': (0, 0, 0),
            '1': (0, 0, 255),
            '2': (0, 128, 0),
            '3': (255, 0, 0),
            '4': (0, 0, 128),
            '5': (128, 0, 0),
            '6': (0, 128, 128),
            '7': (0, 0, 0),
            '8': (128, 128, 128)
        }

    def place_mines(self, first_x, first_y):
        """
        在棋盘上放置地雷，确保第一次点击的位置不会是地雷

        Args:
            first_x: 第一次点击的x坐标
            first_y: 第一次点击的y坐标
        """
        # 创建所有可能的地雷位置列表（排除第一次点击的位置及其周围）
        possible_positions = []
        for y in range(self.height):
            for x in range(self.width):
                # 确保第一次点击位置及其周围8个格子不放地雷
                if abs(x - first_x) > 1 or abs(y - first_y) > 1:
                    possible_positions.append((x, y))

        # 随机选择地雷位置
        mine_positions = random.sample(possible_positions, self.mines)

        # 在选定位置放置地雷
        for x, y in mine_positions:
            self.board[y][x] = -1  # -1表示地雷

        # 计算每个非地雷格子周围的地雷数量
        for y in range(self.height):
            for x in range(self.width):
                if self.board[y][x] != -1:  # 如果不是地雷
                    count = self.count_adjacent_mines(x, y)
                    self.board[y][x] = count

    def count_adjacent_mines(self, x, y):
        """
        计算指定位置周围8个格子中的地雷数量

        Args:
            x: 横坐标
            y: 纵坐标

        Returns:
            周围地雷的数量
        """
        count = 0
        for dy in [-1, 0, 1]:
            for dx in [-1, 0, 1]:
                nx, ny = x + dx, y + dy
                # 检查边界并统计地雷
                if 0 <= nx < self.width and 0 <= ny < self.height:
                    if self.board[ny][nx] == -1:
                        count += 1
        return count

    def reveal(self, x, y):
        """
        揭开指定位置的格子

        Args:
            x: 横坐标
            y: 纵坐标
        """
        # 检查边界
        if not (0 <= x < self.width and 0 <= y < self.height):
            return

        # 如果已经揭开或者标记了旗帜，则不做操作
        if self.revealed[y][x] or self.flagged[y][x]:
            return

        # 第一次点击时放置地雷
        if self.first_click:
            self.place_mines(x, y)
            self.first_click = False

        # 揭开当前格子
        self.revealed[y][x] = True

        # 如果点击到地雷，游戏结束
        if self.board[y][x] == -1:
            self.game_over = True
            return

        # 如果是空白格子（周围没有地雷），则递归揭开周围的格子
        if self.board[y][x] == 0:
            for dy in [-1, 0, 1]:
                for dx in [-1, 0, 1]:
                    self.reveal(x + dx, y + dy)

        # 检查是否获胜
        self.check_win()

    def toggle_flag(self, x, y):
        """
        切换指定位置的旗帜状态

        Args:
            x: 横坐标
            y: 纵坐标
        """
        # 检查边界和是否已经揭开
        if not (0 <= x < self.width and 0 <= y < self.height) or self.revealed[y][x]:
            return

        # 切换旗帜状态
        self.flagged[y][x] = not self.flagged[y][x]

        # 检查是否获胜
        self.check_win()

    def check_win(self):
        """
        检查玩家是否获胜
        """
        for y in range(self.height):
            for x in range(self.width):
                # 如果一个非地雷格子未被揭开，游戏未结束
                if self.board[y][x] != -1 and not self.revealed[y][x]:
                    return

        # 所有非地雷格子都被揭开，获胜
        self.win = True

    def reveal_all_mines(self):
        """
        揭开所有地雷（游戏结束后调用）
        """
        for y in range(self.height):
            for x in range(self.width):
                if self.board[y][x] == -1:
                    self.revealed[y][x] = True

    def reset_game(self):
        """
        重置游戏
        """
        self.board = [[0 for _ in range(self.width)] for _ in range(self.height)]
        self.revealed = [[False for _ in range(self.width)] for _ in range(self.height)]
        self.flagged = [[False for _ in range(self.width)] for _ in range(self.height)]
        self.game_over = False
        self.win = False
        self.first_click = True

    def draw(self):
        """
        绘制游戏界面
        """
        # 填充背景
        self.screen.fill(self.colors['background'])

        # 绘制格子
        for y in range(self.height):
            for x in range(self.width):
                rect = pygame.Rect(
                    x * self.cell_size,
                    y * self.cell_size,
                    self.cell_size,
                    self.cell_size
                )

                # 根据状态绘制格子
                if self.revealed[y][x]:
                    pygame.draw.rect(self.screen, self.colors['revealed'], rect)
                    pygame.draw.rect(self.screen, self.colors['grid'], rect, 1)

                    # 如果是地雷
                    if self.board[y][x] == -1:
                        pygame.draw.circle(
                            self.screen,
                            self.colors['mine'],
                            rect.center,
                            self.cell_size // 3
                        )
                    # 如果是数字
                    elif self.board[y][x] > 0:
                        text = self.font.render(str(self.board[y][x]), True, self.colors[str(self.board[y][x])])
                        text_rect = text.get_rect(center=rect.center)
                        self.screen.blit(text, text_rect)
                else:
                    pygame.draw.rect(self.screen, self.colors['grid'], rect)
                    pygame.draw.rect(self.screen, (100, 100, 100), rect, 2)

                    # 如果标记了旗帜
                    if self.flagged[y][x]:
                        pygame.draw.polygon(
                            self.screen,
                            self.colors['flag'],
                            [
                                (rect.left + self.cell_size // 4, rect.top + self.cell_size // 4),
                                (rect.left + self.cell_size // 4, rect.bottom - self.cell_size // 4),
                                (rect.right - self.cell_size // 4, rect.centery)
                            ]
                        )

        # 显示游戏状态信息
        status_y = self.height * self.cell_size + 10

        # 显示剩余地雷数
        remaining_mines = self.mines - sum(sum(row) for row in self.flagged)
        mines_text = self.font.render(f"剩余地雷: {remaining_mines}", True, self.colors['text'])
        self.screen.blit(mines_text, (10, status_y))

        # 显示游戏结果
        if self.game_over:
            self.reveal_all_mines()
            game_over_text = self.big_font.render("游戏结束！点击重新开始", True, self.colors['mine'])
            text_rect = game_over_text.get_rect(center=(self.window_width // 2, status_y + 20))
            self.screen.blit(game_over_text, text_rect)
        elif self.win:
            win_text = self.big_font.render("恭喜获胜！点击重新开始", True, (0, 128, 0))
            text_rect = win_text.get_rect(center=(self.window_width // 2, status_y + 20))
            self.screen.blit(win_text, text_rect)

        pygame.display.flip()

    def handle_click(self, pos, right_click=False):
        """
        处理鼠标点击事件

        Args:
            pos: 鼠标位置 (x, y)
            right_click: 是否为右键点击
        """
        x, y = pos
        grid_x, grid_y = x // self.cell_size, y // self.cell_size

        # 检查是否在游戏区域内
        if 0 <= grid_x < self.width and 0 <= grid_y < self.height:
            if self.game_over or self.win:
                # 游戏结束后点击任意位置重新开始
                self.reset_game()
            else:
                if right_click:
                    self.toggle_flag(grid_x, grid_y)
                else:
                    self.reveal(grid_x, grid_y)

    def run(self):
        """
        运行游戏主循环
        """
        clock = pygame.time.Clock()

        while True:
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    pygame.quit()
                    sys.exit()

                elif event.type == pygame.MOUSEBUTTONDOWN:
                    self.handle_click(event.pos, event.button == 3)  # 右键为3

            self.draw()
            clock.tick(60)


if __name__ == "__main__":
    # 创建并运行游戏（10x10的网格，10个地雷）
    game = Minesweeper(10, 10, 10)
    game.run()
